//
//  NDKeychainTool.swift
//  NyamanDana
//
//  Created by 李永彬 on 2025/11/4.
//

import Foundation
import Security

let NDIdfvKey = "NDIdfvKey"
class NDKeychainTool {
    
    static let shared = NDKeychainTool()
    private init() {}
    
    // MARK: - 基础操作
    
    /// 保存数据到 Keychain
    func save(_ data: Data, forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: key,
            kSecValueData: data,
            kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock // 首次解锁后可用
        ]
        
        // 先删除已存在的项目
        delete(forKey: key, service: service)
        
        let status = SecItemAdd(query as CFDictionary, nil)
        return status == errSecSuccess
    }
    
    /// 从 Keychain 读取数据
    func read(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Data? {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: key,
            kSecReturnData: true,
            kSecMatchLimit: kSecMatchLimitOne
        ]
        
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        
        guard status == errSecSuccess, let data = result as? Data else {
            return nil
        }
        
        return data
    }
    
    /// 从 Keychain 删除数据
    @discardableResult
    func delete(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: key
        ]
        
        let status = SecItemDelete(query as CFDictionary)
        return status == errSecSuccess || status == errSecItemNotFound
    }
    
    /// 检查 Keychain 中是否存在指定 key
    func contains(key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: key,
            kSecReturnData: false,
            kSecMatchLimit: kSecMatchLimitOne
        ]
        
        let status = SecItemCopyMatching(query as CFDictionary, nil)
        return status == errSecSuccess
    }
    
    // MARK: - 字符串操作
    
    @discardableResult
    func saveString(_ string: String, forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        guard let data = string.data(using: .utf8) else { return false }
        return save(data, forKey: key, service: service)
    }
    
    func readString(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> String? {
        guard let data = read(forKey: key, service: service) else { return nil }
        return String(data: data, encoding: .utf8)
    }
    
    // MARK: - Codable 对象操作
    
    @discardableResult
    func save<T: Encodable>(_ object: T, forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        do {
            let data = try JSONEncoder().encode(object)
            return save(data, forKey: key, service: service)
        } catch {
            print("NDKeychainManager: Failed to encode object - \(error)")
            return false
        }
    }
    
    func read<T: Decodable>(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> T? {
        guard let data = read(forKey: key, service: service) else { return nil }
        
        do {
            let object = try JSONDecoder().decode(T.self, from: data)
            return object
        } catch {
            print("NDKeychainManager: Failed to decode object - \(error)")
            return nil
        }
    }
    
    // MARK: - 批量操作
    
    /// 获取所有保存的 key
    func allKeys(service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> [String] {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecReturnAttributes: true,
            kSecMatchLimit: kSecMatchLimitAll
        ]
        
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        
        guard status == errSecSuccess, let items = result as? [[CFString: Any]] else {
            return []
        }
        
        return items.compactMap { $0[kSecAttrAccount] as? String }
    }
    
    /// 清空所有数据
    func clearAll(service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service
        ]
        
        let status = SecItemDelete(query as CFDictionary)
        return status == errSecSuccess || status == errSecItemNotFound
    }
}

// MARK: - 便捷方法扩展
extension NDKeychainTool {
    
    /// 保存布尔值
    @discardableResult
    func saveBool(_ value: Bool, forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        return saveString(value ? "true" : "false", forKey: key, service: service)
    }
    
    /// 读取布尔值
    func readBool(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        return readString(forKey: key, service: service) == "true"
    }
    
    /// 保存整数
    @discardableResult
    func saveInt(_ value: Int, forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Bool {
        return saveString("\(value)", forKey: key, service: service)
    }
    
    /// 读取整数
    func readInt(forKey key: String, service: String = Bundle.main.bundleIdentifier ?? "com.ndapp.keychain") -> Int? {
        guard let string = readString(forKey: key, service: service) else { return nil }
        return Int(string)
    }
}

// MARK: - 错误处理
enum NDKeychainError: LocalizedError {
    case saveFailed
    case readFailed
    case deleteFailed
    case encodingFailed
    case decodingFailed
    
    var errorDescription: String? {
        switch self {
        case .saveFailed:
            return "save Keychain failed"
        case .readFailed:
            return "read Keychain failed"
        case .deleteFailed:
            return "Keychain failed"
        case .encodingFailed:
            return "failed"
        case .decodingFailed:
            return "failed"
        }
    }
}
